package com.jerome.election.server.handler;

import com.jerome.election.server.ContextUtil;
import com.jerome.election.server.paxos.PaxosMessage;
import com.jerome.election.server.PaxosMethodEnum;
import com.jerome.election.server.PaxosUtil;
import com.jerome.election.storage.ExpiringMap;
import com.jerome.election.sync.SyncClientHandler;
import com.jerome.election.sync.SyncVo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 发起请求服务
 *
 * 扮演角色: Proposer
 *
 * @author Jerome
 * @date 2023/10/18 11:00
 * @version 1.0
 */
public class ClientHandler implements SyncClientHandler {
    @Override
    public void initHandle(Socket socket) throws IOException {
        PaxosUtil.init(getWriter(socket));
    }

    @Override
    public void receiveHandle(Socket socket) throws IOException {
        // 逐行读取
        BufferedReader httpReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
        String line = httpReader.readLine();
        PaxosMessage paxosMessage = new PaxosMessage(line);
        PaxosMethodEnum paxosMethodEnum = PaxosMethodEnum.getByCode(paxosMessage.getMethod());
        switch (paxosMethodEnum){
            case PREPARE:
                //接收选票
                ContextUtil.getProposeAccepter().setQuasiProposalsVotes(paxosMessage.getProposalNumber());
                break;
            case ACCEPT:
                //接受选票
                ContextUtil.getProposeAccepter().setQuasiAcceptsVotes(paxosMessage.getProposalNumber());
                break;
            case PINGPONG:
                //保存心跳
                ContextUtil.getNodeMap().put(Integer.parseInt(paxosMessage.getProposalValue()),true);
                break;
            default:
                break;
        }
    }

    @Override
    public void heartbeatHandle(Socket socket) throws IOException {
        //发送 heartbeat
        PaxosUtil.write(getWriter(socket),new PaxosMessage(PaxosMethodEnum.PINGPONG.getCode(),ContextUtil.getProposeAccepter().getProposalNumber(),ContextUtil.getConfig().getNode()+""));
    }

    @Override
    public void sendHandle(Socket socket, SyncVo syncVo) throws IOException {
        //发送信息
        PaxosUtil.write(getWriter(socket),new PaxosMessage(syncVo.getMethod(),syncVo.getLatestTime(),syncVo.getContent().toString()));
    }

    /**
     * socket 长连接io流
     * Socket:PrintWriter
     */
    private ExpiringMap<Socket, PrintWriter> socketIoMap = new ExpiringMap<>(75000);
    /**
     * 获取输出流
     * @param socket
     * @author songxulin
     * @date 2023/10/31 10:36
     * @return PrintWriter
     */
    private PrintWriter getWriter(Socket socket) throws IOException {
        PrintWriter writer = socketIoMap.get(socket);
        if (writer ==null){
            writer = new PrintWriter(socket.getOutputStream());
        }
        socketIoMap.put(socket,writer);
        return writer;
    }
}
